/*
 * Class: Stopwatch
 * License: BSD
 * Author: Lucifer Xu(colorful1982@gmail.com)
 * Date: 2007-05-13
 * Purpose: Provide a high-resolution performance counter to accurately measure elapsed time.
 */

//oldrev: 似乎这个类在 Posix 类系统下很难实现？ Mono 也没有实现这个


module dotmars.diagnostics.stopwatch;
import dotmars.platform.base;
//import dotmars.diagnostics.timespan;
import dotmars.base.time;
/*
 * 该类提供了一个高分辨率性能计数器，用来准确的测量运行时间。
 * 如果硬件不支持，则使用每秒刻度数来测量。
 * 目前只支持Windows。
 */

//oldrev: 为了能在 Linux 下编译，所以....
//BTW: 不要去碰 Rotor 的代码，那不是自由软件
version(none){

public class Stopwatch
{
    private const long TicksPerMillisecond = 10000;
    private const long TicksPerSecond = TicksPerMillisecond * 1000;

    private long m_elapsed;
    private long m_startTimeStamp;

    /* 获取一个指示 Stopwatch 计时器是否在运行的值 */
    private bool m_isRunning;

    public bool IsRunning()
    {
        return m_isRunning;
    }

    /*
     * 如果硬件支持，Frequency便存储高分辨率性能计数器的频率。
     * 否则存储TicksPerSecond。
     */

    private static long frequency;

    public static long Frequency()
    {
        return frequency;
    }

    private static bool isHighResolution;

    public static bool IsHighResolution()
    {
        return isHighResolution;
    }

    /*
     * 性能计数器频率, 每刻度计数.
     * 它可以加速从高频率性能计数器到刻度数的转换.
     */
    private static double tickFrequency;

    /* 当系统运行时频率是不会改变的，所以我们只需要初始化一次即可 */
    static this()
    {
        /*
         * 其实，这里可以采用避免指针的声明方式。
         * 即extern(Windows) bool QueryPerformanceFrequency(out long frequency);
         * 但是，因为phobos库里的声明方式采用指针。
         * 所以，采用了&运算符来取地址。
         */
		LARGE_INTEGER li;
        if(!QueryPerformanceFrequency(&li))
        {
            isHighResolution = false;
            frequency = TicksPerSecond;
            tickFrequency = 1;
        }
        else
        {
			frequency = li.QuadPart;
            isHighResolution = true;
            tickFrequency = TicksPerSecond;
            tickFrequency /= frequency;
        }
    }
    static ~this() {}
    public this() {Reset();}
    public ~this() {}
    /* 获取计时器机制中的当前最小时间单位数 */
    public static long GetTimestamp()
    {
        if(isHighResolution)
        {
			LARGE_INTEGER timestamp;
            QueryPerformanceCounter(&timestamp); //这里不再需要错误处理，因为前面的代码已经做了保证
            return timestamp.QuadPart;
        }
        else
        {
            /* 这段代码因为当前库的不完善而临时写成，以后随着库的不断完成可能会更改位置 */
            /* 此外，在类内重新写就此代码是为性能着想，编译器会优化 */
            const long TicksPerMinute = TicksPerSecond * 60;
            const long TicksPerHour = TicksPerMinute * 60;
            const long TicksPerDay = TicksPerHour * 24;

            const int DaysPerYear = 365;
            const int DaysPer4Years = DaysPerYear * 4 + 1;
            const int DaysPer100Years = DaysPer4Years * 25 - 1;
            const int DaysPer400Years = DaysPer100Years * 4 + 1;
            const int DaysTo10000 = DaysPer400Years * 25 - 366;
            const int DaysTo1601 = DaysPer400Years * 4;

            const long FileTimeOffset = DaysTo1601 * TicksPerDay;
            const long MinTicks = 0L;
            const long MaxTicks = DaysTo10000 * TicksPerDay - 1;

            const ulong TicksMask = 0x3FFFFFFFFFFFFFFF;
            const ulong KindUtc = 0x4000000000000000;

            /* 得到当前的UTC时间 */
            FILETIME fileTime;
            GetSystemTimeAsFileTime(&fileTime);
            ulong fullTime = (cast(ulong)(fileTime.dwHighDateTime) << 32) | (cast(ulong)fileTime.dwLowDateTime);
            ulong ticks = (fullTime + FileTimeOffset) | KindUtc;

            return cast(long)(ticks & TicksMask);
        }
    }
    /* 开始或继续测量某个时间间隔的运行时间 */
    public void Start()
    {
        if(!m_isRunning)
        {
            m_startTimeStamp = GetTimestamp();
            m_isRunning = true;
        }
    }
    /* 对新的 Stopwatch 实例进行初始化，将运行时间属性设置为零，然后开始测量运行时间 */
    public static Stopwatch StartNew()
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        return watch;
    }
    /* 停止测量某个时间间隔的运行时间 */
    public void Stop()
    {
        if(m_isRunning)
        {
            long endTimeStamp = GetTimestamp();
            long elapsedThisPeriod = endTimeStamp - m_startTimeStamp;
            m_elapsed += elapsedThisPeriod;
            m_isRunning = false;
        }
    }
    /* 停止时间间隔测量，并将运行时间重置为零 */
    public void Reset()
    {
        m_elapsed = 0;
        m_isRunning = false;
        m_startTimeStamp = 0;
    }
    /* 获取当前实例测量得出的总运行时间 */
    public TimeSpan Elapsed()
    {
        return new TimeSpan(GetElapsedDateTimeTicks());
    }
    /* 获取当前实例测量得出的总运行时间（以毫秒为单位） */
    public long ElapsedMilliseconds()
    {
        return GetElapsedDateTimeTicks() / TicksPerMillisecond;
    }
    /* 获取当前实例测量得出的总运行时间（用计时器刻度表示） */
    public long ElapsedTicks()
    {
        return GetRawElapsedTicks();
    }
    // 获得消逝的时间刻度数
    private long GetElapsedDateTimeTicks()
    {
        long rawTicks = GetRawElapsedTicks();
        if(isHighResolution)
        {
            double ticks = rawTicks;
            ticks *= tickFrequency;
            return cast(long) ticks;
        }
        else
        {
            return rawTicks;
        }
    }
    private long GetRawElapsedTicks()
    {
        long timeElapsed = m_elapsed;
        if(m_isRunning)
        {
            long currentTimestamp = GetTimestamp();
            long elapsedUntilNow = currentTimestamp - m_startTimeStamp;
            timeElapsed += elapsedUntilNow;
        }
        return timeElapsed;
    }
}


}//version(none)

